package com.atguigu.tingshu.search.service.impl;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.LongTermsBucket;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.MsearchRequest;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.rank_eval.RankEvalMetricDiscountedCumulativeGain;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.Suggestion;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONCreator;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.CategoryFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.PinYinUtils;
import com.atguigu.tingshu.model.album.*;
import com.atguigu.tingshu.model.search.AlbumInfoIndex;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.model.search.SuggestIndex;
import com.atguigu.tingshu.query.search.AlbumIndexQuery;
import com.atguigu.tingshu.repository.SuggestIndexRepository;
import com.atguigu.tingshu.repository.albumIndexRepository;
import com.atguigu.tingshu.search.service.SearchService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo;
import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.suggest.Completion;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.lang.annotation.Documented;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;


@Slf4j
@Service
@SuppressWarnings({"all"})
public class SearchServiceImpl implements SearchService {
    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;
    @Autowired
    private CategoryFeignClient categoryFeignClient;
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;
    @Autowired
    private albumIndexRepository albumIndexRepository;
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;
    @Autowired
    private ElasticsearchClient elasticsearchClient;
    @Autowired
    private SuggestIndexRepository suggestIndexRepository;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;

    /**
     * 根据分类ID和排名类型查询排名列表
     *
     * @param category1Id 分类1的ID，用于区分不同的排名列表
     * @param ranking 排名类型，用于指定特定的排名
     * @return 返回查询到的排名列表，如果没有找到则可能返回空列表
     *
     * 该方法通过Redis的Hash操作来获取存储的排名信息，减少了数据库查询的次数，提高了效率
     */
    @Override
    public List<AlbumInfoIndex> findRankingList(Long category1Id, String ranking) {
        // 构造Redis键名，使用分类ID和排名类型的组合从Redis中获取排名数据
        List<AlbumInfoIndex> list = (List<AlbumInfoIndex>) this.redisTemplate.opsForHash()
                .get(RedisConstant.RANKING_KEY_PREFIX + category1Id, ranking);
        return list;
    }

    /**
     * 更新排行榜
     */
    @Override
    public void updateLatelyAlbumRanking() {
        // 获取一级分类数据
        Result<List<BaseCategory1>> category1ListResult = categoryFeignClient.findCategory1List();
        // 确保一级分类数据存在
        Assert.notNull(category1ListResult, "一级分类不存在");
        List<BaseCategory1> baseCategory1List = category1ListResult.getData();
        // 确保一级分类数据列表非空
        Assert.notNull(baseCategory1List, "一级分类不存在");
        // 遍历每个一级分类
        for (BaseCategory1 baseCategory1 : baseCategory1List) {
            // 定义排名维度数组
            String[] rankingDimensionArray = new String[]{"hotScore", "playStatNum", "subscribeStatNum", "buyStatNum", "commentStatNum"};
            // 遍历每个排名维度
            for (String rankingDimension : rankingDimensionArray) {
                // 尝试在Elasticsearch中搜索符合条件的专辑信息
                SearchResponse<AlbumInfoIndex> searchResponse = null;
                try {
                    searchResponse = elasticsearchClient.search(s->s.index("albuminfo")
                            .query(q->q.match(m->m.field("category1Id").query(baseCategory1.getId())))
                            .sort(st->st.field(f->f.field(rankingDimension).order(SortOrder.Desc)))
                            , AlbumInfoIndex.class);
                } catch (IOException e) {
                    // 处理可能的IO异常
                    throw new RuntimeException(e);
                }
                // 提取搜索结果中的专辑信息列表
                List<AlbumInfoIndex> albumInfoIndexList = searchResponse.hits().hits().stream().map(Hit::source).collect(Collectors.toList());
                // 将排名数据存入Redis哈希中
                this.redisTemplate.opsForHash().put(RedisConstant.RANKING_KEY_PREFIX + baseCategory1.getId(), rankingDimension, albumInfoIndexList);
            }
        }
    }


    @Override
    /**
     * 根据一级分类ID获取渠道信息
     * 本方法主要通过Feign调用和Elasticsearch搜索来获取相关数据
     * 首先，它查找一级分类ID下的顶级三级分类
     * 然后，在Elasticsearch中搜索与这些三级分类ID相关的专辑信息
     * 最后，将这些信息组织成Map列表返回
     *
     * @param category1Id 一级分类ID
     * @return 包含三级分类信息和相关专辑的List<Map < String, Object>>
     */
    public List<Map<String, Object>> getChannel(Long category1Id) {
        // 获取category3中的top7
        Result<List<BaseCategory3>> topBaseCategory3Result = categoryFeignClient.findTopBaseCategory3(category1Id);
        // 校验数据是否存在
        Assert.notNull(topBaseCategory3Result, "一级分类不存在");
        List<BaseCategory3> baseCategory3List = topBaseCategory3Result.getData();
        // 校验分类数据是否存在
        Assert.notNull(baseCategory3List, "一级分类下没有三级分类");
        // 将分类数据转换为Map以便快速查找
        Map<Long, BaseCategory3> baseCategory3Map = baseCategory3List.stream().collect(Collectors.toMap(BaseCategory3::getId, baseCategory3 -> baseCategory3));
        SearchResponse<AlbumInfoIndex> searchResponse = null;
        List<FieldValue> fieldValueList = baseCategory3List.stream().map(baseCategory3 -> FieldValue.of(baseCategory3.getId())).collect(Collectors.toList());

        // 执行Elasticsearch搜索操作，使用suggest功能从suggestinfo索引中获取建议
        try {
            searchResponse = elasticsearchClient.search(s -> s.index("albuminfo")
                    .query(q -> q.terms(t -> t.field("category3Id").terms(t1 -> t1.value(fieldValueList))))
                    .aggregations("categoryAgg", a -> a.terms(t -> t.field("category3Id"))
                            .aggregations("topSixAgg", a1 -> a1.topHits(to -> to.size(6)
                                    .sort(st -> st.field(f -> f.field("hotScore").order(SortOrder.Desc)))))), AlbumInfoIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 从聚合中获取数据
        List<LongTermsBucket> bucketList = searchResponse.aggregations().get("categoryAgg").lterms().buckets().array();
        // 判断集合是否为空
        if (!CollectionUtils.isEmpty(bucketList)) {
            // 声明一个map集合
            List<Map<String, Object>> hashMapList = bucketList.stream().map(termsBucket -> {
                // 创建一个map集合
                HashMap<String, Object> hashMap = new HashMap<>();
                // 获取key，key就是三级分类Id
                long category3Id = termsBucket.key();
                // 获取三级分类的结合列表
                List<AlbumInfoIndex> albumInfoIndexList = termsBucket.aggregations().get("topSixAgg").topHits().hits().hits().stream().map(hit -> {
                    // 获取数据
                    String jsonData = hit.source().toString();
                    // 数据类型专辑
                    AlbumInfoIndex albumInfoIndex = JSONObject.parseObject(jsonData, AlbumInfoIndex.class);
                    return albumInfoIndex;
                }).collect(Collectors.toList());
                // 通过三级分类Id获取到三级分类对象
                hashMap.put("baseCategory3", baseCategory3Map.get(category3Id));
                hashMap.put("list", albumInfoIndexList);
                return hashMap;
            }).collect(Collectors.toList());
            return hashMapList;
        }

        return new ArrayList<>();
    }


    /**
     * 根据关键字完成建议列表
     * 该方法使用Elasticsearch的suggest功能，根据给定的关键字keyWord生成相关的建议列表
     *
     * @param keyWord 用户输入的关键字，用于生成建议
     * @return 返回一个包含与关键字相关的建议字符串列表
     */
    @Override
    public List<String> completeSuggest(String keyWord) {
        List<String> list = new ArrayList<>();
        SearchResponse<SuggestIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(
                    s -> s.index("suggestinfo")
                            .suggest(sg -> sg.suggesters("keyword-suggest", s1 -> s1.prefix(keyWord)
                                            .completion(c -> c.field("keyword")
                                                    .skipDuplicates(true)
                                                    .fuzzy(f -> f.fuzziness("auto"))
                                                    .size(10)))
                                    .suggesters("keywordPinyin-suggest", s1 -> s1.prefix(keyWord)
                                            .completion(c -> c.field("keywordPinyin")
                                                    .skipDuplicates(true)
                                                    .fuzzy(f -> f.fuzziness("auto"))
                                                    .size(10)))
                                    .suggesters("keywordSequence-suggest", s1 -> s1.prefix(keyWord)
                                            .completion(c -> c.field("keywordSequence")
                                                    .skipDuplicates(true)
                                                    .fuzzy(f -> f.fuzziness("auto"))
                                                    .size(10)))
                            )
                    ,
                    SuggestIndex.class);
        } catch (IOException e) {
            // 捕获并处理IO异常，避免程序因未处理的异常而终止
            throw new RuntimeException(e);
        }
        // 从搜索响应中提取建议结果，并添加到返回列表中
        list.addAll(this.getSuggestResult(searchResponse, "keyword-suggest"));
        list.addAll(this.getSuggestResult(searchResponse, "keywordPinyin-suggest"));
        list.addAll(this.getSuggestResult(searchResponse, "keywordSequence-suggest"));


        if (list.size()<10){
            SearchResponse<SuggestIndex> response = null;
            try {
                response=elasticsearchClient.search(s->s.index("suggestinfo").query(q->q.match(m->m.field("title").query("keyWord"))), SuggestIndex.class);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            for (Hit<SuggestIndex> hit : response.hits().hits()) {
                String title = hit.source().getTitle();
                list.add(title);
                if (list.size()>=10){
                    return list;
                }
            }
        }
        return list;
    }

    /**
     * 根据搜索响应获取建议结果列表
     *
     * @param searchResponse 搜索响应对象，包含建议数据
     * @param type           建议类型，用于从搜索响应中获取特定类型的建议
     * @return 返回一个字符串集合，包含根据建议类型获取的标题列表如果未找到相关建议，则返回一个空列表
     */
    private Collection<String> getSuggestResult(SearchResponse<SuggestIndex> searchResponse, String type) {
        // 根据建议类型从搜索响应中获取建议列表
        List<Suggestion<SuggestIndex>> suggestionList = searchResponse.suggest().get(type);
        // 检查建议列表是否非空
        if (!CollectionUtils.isEmpty(suggestionList)) {
            // 遍历建议列表，处理每个建议对象，提取并返回标题列表
            for (Suggestion<SuggestIndex> suggestIndexSuggestion : suggestionList) {
                // 使用stream API对建议选项进行映射，提取标题并收集到列表中
                List<String> list = suggestIndexSuggestion.completion().options().stream()
                        .map(o -> {
                            SuggestIndex suggestIndex = o.source();
                            return suggestIndex.getTitle();
                        }).collect(Collectors.toList());
                // 返回收集到的标题列表
                return list;
            }

        }

        // 如果建议列表为空，则返回一个空的列表
        return new ArrayList<>();
    }


    /**
     * 重写搜索方法以实现专辑信息的搜索功能
     *
     * @param albumIndexQuery 专辑索引查询对象，包含搜索参数
     * @return AlbumSearchResponseVo 返回专辑搜索的响应数据对象
     */
    @Override
    public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) {
        // 根据用户输入动态生成DSL查询语句
        SearchRequest searchRequest = this.queryBuilderDslQuery(albumIndexQuery);
        SearchResponse<AlbumInfoIndex> searchResponse = null;

        // 执行ES搜索请求
        try {
            searchResponse = this.elasticsearchClient.search(searchRequest, AlbumInfoIndex.class);
        } catch (IOException e) {
            // 捕获IO异常并抛出运行时异常
            throw new RuntimeException(e);
        }

        // 解析搜索结果数据
        AlbumSearchResponseVo albumSearchResponseVo = this.parseResultData(searchResponse);

        // 设置搜索结果总数
        albumSearchResponseVo.setTotal(searchResponse.hits().total().value());
        // 设置当前页码
        albumSearchResponseVo.setPageNo(albumIndexQuery.getPageNo());
        // 设置页面大小
        albumSearchResponseVo.setPageSize(albumIndexQuery.getPageSize());
        // 计算总页数并向上取整
        Long total = searchResponse.hits().total().value();
        Integer pageSize = albumIndexQuery.getPageSize();
        Long totalPages = total % pageSize == 0 ? total / pageSize : total / pageSize + 1;
        //  Long i = (total + pageSize - 1) / pageSize;
        albumSearchResponseVo.setTotalPages(totalPages);
        //  返回对象

        return albumSearchResponseVo;
    }

    /**
     * 解析搜索结果数据
     * 将Elasticsearch的搜索结果解析并转换为自定义的响应对象
     *
     * @param searchResponse Elasticsearch返回的搜索响应对象
     * @return 返回解析后的AlbumSearchResponseVo对象，包含搜索结果的列表
     */
    private AlbumSearchResponseVo parseResultData(SearchResponse<AlbumInfoIndex> searchResponse) {
        // 初始化AlbumSearchResponseVo对象，用于封装最终的搜索结果
        AlbumSearchResponseVo searchResponseVo = new AlbumSearchResponseVo();

        // 对搜索结果的命中项进行流式处理，转换每个命中项为AlbumInfoIndexVo对象
        List<AlbumInfoIndexVo> albumInfoIndexVoList = searchResponse.hits().hits().stream().map(
                hit -> {
                    // 获取源数据并实例化AlbumInfoIndex对象
                    AlbumInfoIndex albumInfoIndex = hit.source();
                    // 初始化AlbumInfoIndexVo对象，用于封装要返回的搜索结果项
                    AlbumInfoIndexVo albumInfoIndexVo = new AlbumInfoIndexVo();
                    // 将AlbumInfoIndex对象的属性复制到AlbumInfoIndexVo对象
                    BeanUtils.copyProperties(albumInfoIndex, albumInfoIndexVo);
                    // 如果高亮字段存在且不为空，则设置高亮的专辑标题
                    if (!CollectionUtils.isEmpty(hit.highlight().get("albumtitle"))) {
                        albumInfoIndexVo.setAlbumTitle(hit.highlight().get("albumtitle").get(0));
                    }
                    // 返回转换后的AlbumInfoIndexVo对象
                    return albumInfoIndexVo;
                }
        ).collect(Collectors.toList());

        // 将转换后的搜索结果列表设置到返回对象中
        searchResponseVo.setList(albumInfoIndexVoList);
        // 返回解析后的搜索结果对象
        return searchResponseVo;
    }

    /**
     * 构建搜索请求的DSL查询
     * 该方法主要用于构建一个搜索请求，根据提供的专辑索引查询对象来设置各种搜索参数
     * 包括关键词搜索、分类ID搜索、属性搜索、分页和排序等
     *
     * @param albumIndexQuery 专辑索引查询对象，包含搜索参数如关键词、分类ID、属性、分页和排序信息
     * @return 构建好的搜索请求对象
     */
    private SearchRequest queryBuilderDslQuery(AlbumIndexQuery albumIndexQuery) {
        //创建并初始化一个搜索请求构建器
        SearchRequest.Builder searchRequestBuilder = new SearchRequest.Builder();
        //设置需要搜索的索引库名称
        searchRequestBuilder.index("albuminfo");
        //  创建Query 对象
        Query.Builder queryBuilder = new Query.Builder();
        //  创建BoolQuery对象
        BoolQuery.Builder boolQueryBuilder = new BoolQuery.Builder();
        //  判断当前是否根据关键词检索
        if (!StringUtils.isEmpty(albumIndexQuery.getKeyword())) {
            boolQueryBuilder.should(s -> s.match(m -> m.field("albumTitle").query(albumIndexQuery.getKeyword())))
                    .should(s -> s.match(m -> m.field("albumIntro").query(albumIndexQuery.getKeyword())));

            //  高亮：
            searchRequestBuilder.highlight(h -> h.fields("albumTitle", hf -> hf.preTags("<span style=color:#f86442>").postTags("</span>")));
        }
        //  判断是否根据分类Id 检索
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory1Id())) {
            boolQueryBuilder.filter(f -> f.term(t -> t.field("category1Id").value(albumIndexQuery.getCategory1Id())));
        }
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory2Id())) {
            boolQueryBuilder.filter(f -> f.term(t -> t.field("category2Id").value(albumIndexQuery.getCategory2Id())));
        }
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory3Id())) {
            boolQueryBuilder.filter(f -> f.term(t -> t.field("category3Id").value(albumIndexQuery.getCategory3Id())));
        }
        //  根据属性与属性值进行过滤
        List<String> attributeList = albumIndexQuery.getAttributeList();
        if (!CollectionUtils.isEmpty(attributeList)) {
            for (String attribute : attributeList) {
                //  attribute: 属性id:属性值id
                String[] split = attribute.split(":");
                //  判断是否是为空
                if (null != split && split.length == 2) {
                    boolQueryBuilder.filter(f -> f.nested(n -> n.path("attributeValueIndexList").query(
                            q -> q.bool(b -> b.filter(fl -> fl.term(t -> t.field("attributeValueIndexList.attributeId").value(split[0])))
                                    .filter(fl -> fl.term(t -> t.field("attributeValueIndexList.valueId").value(split[1])))
                            )
                    )));
                }
            }
        }

            //将构建好的布尔查询设置到查询构建器中
        queryBuilder.bool(boolQueryBuilder.build());
        searchRequestBuilder.query(queryBuilder.build());
        //设置分页参数
        searchRequestBuilder.from((albumIndexQuery.getPageNo() - 1) * albumIndexQuery.getPageSize());
        searchRequestBuilder.size(albumIndexQuery.getPageSize());
        //如果排序参数不为空，设置排序条件
        String order = albumIndexQuery.getOrder();
        if (!StringUtils.isEmpty(order)) {
            String[] split = order.split(":");
            String field = null;
            //根据排序类型设置排序字段
            switch (split[0]) {
                case "1":
                    field = "hotScore";
                    break;
                case "2":
                    field = "playStatNum";
                    break;
                case "3":
                    field = "createTime";
                    break;
            }
            //根据排序方式设置升序或降序
            String finalField = field;
            searchRequestBuilder.sort(s -> s.field(f -> f.field(finalField).order("asc".equals(split[1]) ? SortOrder.Asc : SortOrder.Desc)));
        }
        //返回构建好的搜索请求
        SearchRequest request = searchRequestBuilder.build();
        log.info("dsl语句：" + searchRequestBuilder);
        System.out.println(searchRequestBuilder.toString());
        //  返回
        return request;
    }

    /**
     * 上架专辑
     *
     * @param albumId 专辑ID
     */
    @Override
    public void upperAlbum(Long albumId) {
        // 创建专辑索引对象
        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex();

        // 异步获取专辑信息
        CompletableFuture<AlbumInfo> albumInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            // 调用Feign客户端获取专辑信息
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(albumId);
            // 校验专辑信息是否存在
            Assert.notNull(albumInfoResult, "专辑信息不存在");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo, "专辑信息不存在");
            // 将专辑信息拷贝到索引对象
            BeanUtils.copyProperties(albumInfo, albumInfoIndex);
            return albumInfo;
        }, threadPoolExecutor);

        // 异步获取专辑属性信息
        CompletableFuture<Void> attrCompletableFuture = albumInfoCompletableFuture.runAsync(() -> {
            // 调用Feign客户端获取专辑属性值
            Result<List<AlbumAttributeValue>> albumAttributeValueResult = albumInfoFeignClient.findAlbumAttributeValue(albumId);
            // 校验专辑属性信息是否存在
            Assert.notNull(albumAttributeValueResult, "专辑属性信息不存在");
            List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueResult.getData();
            Assert.notNull(albumAttributeValueList, "专辑属性信息不存在");
            // 转换专辑属性值并设置到索引对象
            List<AttributeValueIndex> attributeValueIndexList = albumAttributeValueList.stream().map(albumAttributeValue -> {
                AttributeValueIndex attributeValueIndex = new AttributeValueIndex();
                attributeValueIndex.setAttributeId(albumAttributeValue.getAttributeId());
                attributeValueIndex.setValueId(albumAttributeValue.getValueId());
                return attributeValueIndex;
            }).toList();
            albumInfoIndex.setAttributeValueIndexList(attributeValueIndexList);
        }, threadPoolExecutor);

        // 异步获取专辑分类信息
        CompletableFuture<Void> categoryCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            // 调用Feign客户端获取专辑分类视图
            Result<BaseCategoryView> categoryViewResult = categoryFeignClient.getCategoryView(albumInfo.getCategory3Id());
            // 校验专辑分类信息是否存在
            Assert.notNull(categoryViewResult, "专辑分类信息不存在");
            BaseCategoryView baseCategoryView = categoryViewResult.getData();
            Assert.notNull(baseCategoryView, "专辑分类信息不存在");
            // 设置专辑分类ID到索引对象
            albumInfoIndex.setCategory1Id(baseCategoryView.getCategory1Id());
            albumInfoIndex.setCategory2Id(baseCategoryView.getCategory2Id());
        }, threadPoolExecutor);

        // 异步获取用户信息
        CompletableFuture<Void> userCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            // 调用Feign客户端获取用户信息
            Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfoVo(albumInfo.getUserId());
            UserInfoVo userInfoVo = userInfoVoResult.getData();
            // 校验用户信息是否存在
            Assert.notNull(userInfoVo, "用户信息不存在");
            // 设置主播名称到索引对象
            albumInfoIndex.setAnnouncerName(userInfoVo.getNickname());
        }, threadPoolExecutor);
        //初始化赋值
        Integer playStatNum = new Random().nextInt(100000);
        Integer subscribeStatNum = new Random().nextInt(100000);
        Integer buyStatNum = new Random().nextInt(100000);
        Integer commentStatNum = new Random().nextInt(100000);
        Double hotScore = new Random().nextDouble(1000);
        albumInfoIndex.setPlayStatNum(playStatNum);
        albumInfoIndex.setSubscribeStatNum(subscribeStatNum);
        albumInfoIndex.setBuyStatNum(buyStatNum);
        albumInfoIndex.setCommentStatNum(commentStatNum);
        albumInfoIndex.setHotScore(hotScore);


        // 等待所有异步任务完成
        CompletableFuture.allOf(albumInfoCompletableFuture, attrCompletableFuture, categoryCompletableFuture, userCompletableFuture).join();

        // 保存专辑索引信息
        albumIndexRepository.save(albumInfoIndex);

        //设置自动补全
        SuggestIndex suggestIndex = new SuggestIndex();
        //设置标题补全
        suggestIndex.setId(UUID.randomUUID().toString().replace("-", ""));
        suggestIndex.setTitle(albumInfoIndex.getAlbumTitle());
        suggestIndex.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumTitle()}));
        suggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumTitle())}));
        suggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumTitle())}));
        //设置简介自动补全
        suggestIndex.setId(UUID.randomUUID().toString().replace("-", ""));
        suggestIndex.setTitle(albumInfoIndex.getAlbumIntro());
        suggestIndex.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumIntro()}));
        suggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumTitle())}));
        suggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumTitle())}));
        suggestIndexRepository.save(suggestIndex);
        // 添加专辑ID到布隆过滤器
        RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
        bloomFilter.add(albumId);
    }

    /**
     * 下架专辑
     *
     * @param albumId 专辑ID
     */
    @Override
    public void lowerAlbum(Long albumId) {
        albumIndexRepository.deleteById(albumId);
    }
}
